﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System.Threading;

namespace MvdDonk.Bomberman.Lib
{
    

    public class MovementUpdateEventArgs : EventArgs
    {
        public MovementUpdateEventArgs(EntityMovementState movementState, Vector2 movementVector, long id, bool isLocalPlayer)
        {
            Id = id;
            IsLocalPlayer = isLocalPlayer;
            MovementState = movementState;
            MovementVector = movementVector;
        }

        public EntityMovementState MovementState { get; private set; }
        public long Id { get; private set; }
        public bool IsLocalPlayer { get; private set; }
        public Vector2 MovementVector { get; private set; }
    }

    public class PositionSyncEventArgs : EventArgs
    {
        public PositionSyncEventArgs(Vector2 position, long id, bool isLocalPlayer)
        {
            Id = id;
            IsLocalPlayer = isLocalPlayer;
            Position = position;
        }

        public long Id { get; private set; }
        public bool IsLocalPlayer { get; private set; }
        public Vector2 Position { get; private set; }
    }

    

    public class Client
    {
        private NetClient client;
        private int serverPort;
        private int syncServerIntervalInMiliseconds = 200;
        private TimeSpan syncServerTimer;

        private int intervalInMiliseconds = 50;
        private TimeSpan serverTimer;

        public delegate void MovementUpdateEventHandler(object sender, MovementUpdateEventArgs e);
        public event MovementUpdateEventHandler MovementUpdate;

        public delegate void PositionSyncEventHandler(object sender, PositionSyncEventArgs e);
        public event PositionSyncEventHandler PositionSync;

        public Client(string serverName, int serverPort)
        {
            Console.WriteLine("Initializing client");
            this.serverPort = serverPort;
            var config = new NetPeerConfiguration(serverName);
            config.EnableMessageType(NetIncomingMessageType.DiscoveryResponse);

            client = new NetClient(config);
            Console.WriteLine("Starting client...");
            client.Start();
        }

        public void FindServer()
        {
            Console.WriteLine("Looking for servers");
            client.DiscoverLocalPeers(serverPort);
        }

        public void Poll()
        {
            // read messages
            NetIncomingMessage msg;
            while ((msg = client.ReadMessage()) != null)
            {
                switch (msg.MessageType)
                {
                    case NetIncomingMessageType.DiscoveryResponse:
                        Console.WriteLine("Found a server on: " + msg.SenderEndpoint.Address + ":" + msg.SenderEndpoint.Port);
                        // just connect to first server discovered
                        client.Connect(msg.SenderEndpoint);
                        break;
                    case NetIncomingMessageType.Data:
                        //Console.WriteLine("Received data from server");
                        // server sent a position update
                        var receivedMsg = MessageFinder.GetMessageFromServer(msg);
                        if (receivedMsg is MovementMessage)
                        {
                            var typed = receivedMsg as MovementMessage;
                            MovementUpdate(this, new MovementUpdateEventArgs(typed.MovementState, typed.MovementVector, receivedMsg.NetworkId, client.UniqueIdentifier == typed.NetworkId));
                        }
                        if (receivedMsg is PositionMessage)
                        {
                            var typed = receivedMsg as PositionMessage;
                            PositionSync(this, new PositionSyncEventArgs(typed.Position, receivedMsg.NetworkId, client.UniqueIdentifier == typed.NetworkId));
                        }
                        break;
                }
            }
        }

        public void UpdateMovement( EntityMovementState movementState, Vector2 movementVector)
        {
            var msg = new MovementMessage(movementVector, movementState);
            msg.SendToServer(client);
        }

        public void SyncPosition( Vector2 position)
        {
            var msg = new PositionMessage(position);
            msg.SendToServer(client);

            ////Console.WriteLine(string.Format("Sending our position to server [{0}, {1}]", x, y));
            //NetOutgoingMessage om = client.CreateMessage();
            //om.Write('M');
            //switch (direction)
            //{
            //    case EntityMovementState.WalkingDown: om.Write('D'); break;
            //    case EntityMovementState.WalkingUp: om.Write('U'); break;
            //    case EntityMovementState.WalkingLeft: om.Write('L'); break;
            //    case EntityMovementState.WalkingRight: om.Write('R'); break;
            //    case EntityMovementState.Idle: om.Write('I'); break;
            //}
            //om.Write(direction == EntityMovementState.Idle ? 0f : speed);
            //om.Write(movementVector.X);
            //om.Write(movementVector.Y);
            //client.SendMessage(om, NetDeliveryMethod.Unreliable);



            //// if needed send position to server
            //syncServerTimer = syncServerTimer.Add(gameTime.ElapsedGameTime);
            //if (syncServerTimer.Milliseconds >= syncServerIntervalInMiliseconds)
            //{
            //    syncServerTimer = new TimeSpan();
            //    short x = (short)position.X;
            //    short y = (short)position.Y;
            //    Console.WriteLine(string.Format("Sending our position to server [{0}, {1}]", x, y));
            //    NetOutgoingMessage om = client.CreateMessage();
            //    om.Write('P');
            //    om.Write(x);
            //    om.Write(y);
            //    client.SendMessage(om, NetDeliveryMethod.Unreliable);
            //}
        }


    }
}
